package annotool;

import ij.ImagePlus;

import java.awt.Component;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;

import annotool.io.LabelReader;

public class AnnImageTable {

	String showIcon = "images/Zoom16.gif";

	String[] children = null;
	int[][] targets;
	String directory = null;
	JScrollPane scrollPane = null;
	JTable table = null;
	annotool.io.DataInput problem = null;
	//Object[][] tabledata = null;
	int numOfAnno;
	java.util.ArrayList<String> annotations; //labels

	AnnImageTable()
	{	}

	public JScrollPane buildImageTable(String directory, String targetFile, String ext)
	{
		this.directory = directory;
		problem = new annotool.io.DataInput(directory,ext);//(String) extBox.getSelectedItem());
		children = problem.getChildren();

		//error checking:
		if (children == null)
		{
			javax.swing.JOptionPane.showMessageDialog(null,"Error: File path may be incorrect.");
			return null;
		}	
		if (children.length == 0)
		{
			javax.swing.JOptionPane.showMessageDialog(null,"There is no image with the given extension.");
			return null;
		}
		//get the targets
		try
		{
			LabelReader labelReader = new LabelReader(children.length);
			targets = labelReader.getTargets(targetFile,children);
			numOfAnno = labelReader.getNumOfAnnotations();
			annotations = labelReader.getAnnotations();
		}catch(Exception e)
		{
			e.printStackTrace();
			javax.swing.JOptionPane.showMessageDialog(null,"Error in reading target file.");
			return null;
		}

		//build up the JTable
		final String[] columnNames;
		columnNames = new String[numOfAnno + 2];
		columnNames[0] = "file";
		columnNames[1]= "show";
		for(int i= 0; i < numOfAnno; i++)
			columnNames[2+i] = annotations.get(i);

		final Object[][] tabledata = new Object[children.length][columnNames.length];
		JButton[] showButtons = new JButton[children.length];
		for (int i = 0; i < children.length; i++)
		{
			showButtons[i] = new JButton(new ImageIcon(showIcon));
			tabledata[i][0] = children[i];
			tabledata[i][1] = showButtons[i];
			for (int j = 0; j < numOfAnno; j++)
				//targets are stored by one annotation per row	
				tabledata[i][2+j] = targets[j][i];
		}		

		// Create a model of the data. 
		javax.swing.table.TableModel dataModel = new javax.swing.table.AbstractTableModel() { 
			public int getColumnCount() { return columnNames.length; } 
			public int getRowCount() { return tabledata.length;} 
			public Object getValueAt(int row, int col) {return tabledata[row][col];} 
			public String getColumnName(int column) {return columnNames[column];} 
			public Class getColumnClass(int c) {return getValueAt(0, c).getClass();} 
			public boolean isCellEditable(int row, int col) {return false ;} 
			public void setValueAt(Object aValue, int row, int column) 
			{ tabledata[row][column] = aValue; 
			fireTableCellUpdated(row, column); //needed if data could change
			} 
		}; 

		TableCellRenderer defaultRenderer;
		table = new JTable(dataModel);
		defaultRenderer = table.getDefaultRenderer(JButton.class);
		table.setDefaultRenderer(JButton.class,
				new JTableButtonRenderer(defaultRenderer));

		scrollPane = new JScrollPane(table);
		scrollPane.setOpaque(true); //content panes must be opaque

		//table.setFillsViewportHeight(true);
		//table.setPreferredScrollableViewportSize(new java.awt.Dimension(400, 600));
		table.addMouseListener(new JTableButtonMouseListener(table));
		/*
		if(children.length < 30) //if there are too many rows, use default height 
		{
			int rowHeight = scrollPane.getSize().height/(children.length+1);
			table.setRowHeight(rowHeight-1);
		}*/

		return scrollPane;
	}

	//update the table after annotation is done
	public void updateTable(Annotation[][] predictions)
	{
		final String[] columnNames;
		columnNames = new String[numOfAnno+numOfAnno+ 2];
		columnNames[0] = "file";
		columnNames[1]= "show";
		for(int i= 0; i < numOfAnno; i++)
			columnNames[2+i] = annotations.get(i);
		for(int i= numOfAnno; i < numOfAnno+numOfAnno; i++)
			columnNames[2+i] = "annotation " +annotations.get(i-numOfAnno);

		final Object[][] tabledata = new Object[children.length][columnNames.length];
		JButton[] showButtons = new JButton[children.length];
		for (int i = 0; i < children.length; i++)
		{
			showButtons[i] = new JButton(new ImageIcon(showIcon));
			tabledata[i][0] = children[i];
			tabledata[i][1] = showButtons[i];
			for (int j = 0; j < numOfAnno; j++)
				tabledata[i][2+j] = targets[j][i];
			for (int j = numOfAnno; j < numOfAnno+numOfAnno; j++)
				tabledata[i][2+j] = predictions[j-numOfAnno][i].anno;
		}		

		javax.swing.table.TableModel dataModel = new javax.swing.table.AbstractTableModel() { 
			public int getColumnCount() { return columnNames.length; } 
			public int getRowCount() { return tabledata.length;} 
			public Object getValueAt(int row, int col) {return tabledata[row][col];} 
			public String getColumnName(int column) {return columnNames[column];} 
			public Class getColumnClass(int c) {return getValueAt(0, c).getClass();} 
			public boolean isCellEditable(int row, int col) {return false ;} 
			public void setValueAt(Object aValue, int row, int column) 
			{ tabledata[row][column] = aValue; 
			fireTableCellUpdated(row, column); //needed if data could change
			} 
		}; 
		//update the model
		table.setModel(dataModel);
	}

	//called after a button click in the table
	private void displayImageInPanel(int index)
	{
		ImagePlus imgp = new ImagePlus(directory+children[index]); 
		//System.out.println("display image:"+directory+children[index]);
		imgp.show();
	}

	//inner class to help render a button in a table
	class JTableButtonRenderer implements TableCellRenderer {
		private TableCellRenderer defaultRenderer;

		public JTableButtonRenderer(TableCellRenderer renderer) {
			defaultRenderer = renderer;
		}

		public Component getTableCellRendererComponent(JTable table, Object value,
				boolean isSelected,
				boolean hasFocus,
				int row, int column)
		{
			if(value instanceof Component)
				return (Component)value;
			return defaultRenderer.getTableCellRendererComponent(
					table, value, isSelected, hasFocus, row, column);
		}
	}

	//an inner class to help the buttons in the table to get the event
	//modified from http://www.devx.com/getHelpOn/10MinuteSolution/20425
	//by Daniel F. Savarese
	class JTableButtonMouseListener implements MouseListener {
		private JTable innertable;

		private void forwardEventToButton(MouseEvent e) {
			TableColumnModel columnModel = innertable.getColumnModel();
			int column = columnModel.getColumnIndexAtX(e.getX());
			int row    = e.getY() / innertable.getRowHeight();
			Object value;
			JButton button;
			MouseEvent buttonEvent;

			if(row >= innertable.getRowCount() || row < 0 ||
					column >= innertable.getColumnCount() || column < 0)
				return;

			value = innertable.getValueAt(row, column);

			if(!(value instanceof JButton))
				return;

			//get a mouse event
			button = (JButton)value;
			System.out.println("get a button event at row " + row);

			buttonEvent =
				(MouseEvent)SwingUtilities.convertMouseEvent(innertable, e, button);
			button.dispatchEvent(buttonEvent);
			innertable.repaint();

			displayImageInPanel(row);
			// This is necessary so that when a button is pressed and released
			// it gets rendered properly.  Otherwise, the button may still appear
			// pressed down when it has been released.
		}

		public JTableButtonMouseListener(JTable table) {
			innertable = table;
		}

		public void mouseClicked(MouseEvent e) {
			forwardEventToButton(e);
		}

		public void mouseEntered(MouseEvent e) {
			//forwardEventToButton(e);
		}

		public void mouseExited(MouseEvent e) {
			//forwardEventToButton(e);
		}

		public void mousePressed(MouseEvent e) {
			//forwardEventToButton(e);
		}

		public void mouseReleased(MouseEvent e) {
			//forwardEventToButton(e);
		}
	} //end of innerclass

}
